package com.suncky.frame.utils;

import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Build;

import androidx.preference.PreferenceManager;

import com.suncky.frame.AppConfig;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@SuppressLint("ApplySharedPref")
public class PreferenceHelper {

    private static final String MODULE_DEFAULT = "default";

    private SharedPreferences mPreferences;

    private static class Holder {
        private static final PreferenceHelper sInstance = new PreferenceHelper();
    }

    public static PreferenceHelper getInstance() {
        return Holder.sInstance;
    }

    private PreferenceHelper() {
    }

    public SharedPreferences getPreferences() {
        if (mPreferences == null) {
            mPreferences = PreferenceManager.getDefaultSharedPreferences(AppConfig.getAppContext());
        }
        return mPreferences;
    }

    public String getString(String moduleName, String key, String defValue) {
        return getPreferences().getString(moduleName + "_" + key, defValue);
    }

    public String getString(String key, String defValue) {
        return getString(MODULE_DEFAULT, key, defValue);
    }

    public void saveString(String moduleName, String key, String value) {
        saveString(moduleName, key, value, false);
    }

    public void saveString(String moduleName, String key, String value, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isSync || isBelowGingerBread()) {
                getPreferences().edit().putString(moduleName + "_" + key, value).commit();
            } else {
                getPreferences().edit().putString(moduleName + "_" + key, value).apply();
            }
        }
    }

    public void saveString(String key, String value) {
        saveString(MODULE_DEFAULT, key, value);
    }

    public Set<String> getStringSet(String moduleName, String key, Set<String> defValues) {
        return getPreferences().getStringSet(moduleName + "_" + key, defValues);
    }

    public Set<String> getStringSet(String key, Set<String> defValues) {
        return getStringSet(MODULE_DEFAULT, key, defValues);
    }

    public void saveStringSet(String moduleName, String key, Set<String> values) {
        if (moduleName != null && key != null) {
            if (isBelowGingerBread()) {
                getPreferences().edit().putStringSet(moduleName + "_" + key, values).commit();
            } else {
                getPreferences().edit().putStringSet(moduleName + "_" + key, values).apply();
            }
        }
    }

    public void saveStringSet(String key, Set<String> values) {
        saveStringSet(MODULE_DEFAULT, key, values);
    }

    public int getInt(String moduleName, String key, int defValue) {
        return getPreferences().getInt(moduleName + "_" + key, defValue);
    }

    public int getInt(String key, int defValue) {
        return getInt(MODULE_DEFAULT, key, defValue);
    }

    public void saveInt(String moduleName, String key, int value) {
        saveInt(moduleName, key, value, false);
    }

    public void saveInt(String moduleName, String key, int value, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isSync || isBelowGingerBread()) {
                getPreferences().edit().putInt(moduleName + "_" + key, value).commit();
            } else {
                getPreferences().edit().putInt(moduleName + "_" + key, value).apply();
            }
        }
    }

    public void saveInt(String key, int value) {
        saveInt(MODULE_DEFAULT, key, value);
    }

    public long getLong(String moduleName, String key, long defValue) {
        return getPreferences().getLong(moduleName + "_" + key, defValue);
    }

    public long getLong(String key, long defValue) {
        return getLong(MODULE_DEFAULT, key, defValue);
    }

    public void saveLong(String moduleName, String key, long value, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isSync || isBelowGingerBread()) {
                getPreferences().edit().putLong(moduleName + "_" + key, value).commit();
            } else {
                getPreferences().edit().putLong(moduleName + "_" + key, value).apply();
            }
        }
    }

    public void saveLong(String moduleName, String key, long value) {
        saveLong(moduleName, key, value, false);
    }

    public void saveLong(String key, long value) {
        saveLong(MODULE_DEFAULT, key, value);
    }

    public float getFloat(String moduleName, String key, float defValue) {
        return getPreferences().getFloat(moduleName + "_" + key, defValue);
    }

    public float getFloat(String key, float defValue) {
        return getFloat(MODULE_DEFAULT, key, defValue);
    }

    public void saveFloat(String moduleName, String key, float value) {
        saveFloat(moduleName, key, value, false);
    }

    public void saveFloat(String moduleName, String key, float value, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isSync || isBelowGingerBread()) {
                getPreferences().edit().putFloat(moduleName + "_" + key, value).commit();
            } else {
                getPreferences().edit().putFloat(moduleName + "_" + key, value).apply();
            }
        }
    }

    public void saveFloat(String key, float value) {
        saveFloat(MODULE_DEFAULT, key, value);
    }

    public boolean getBoolean(String moduleName, String key, boolean defValue) {
        return getPreferences().getBoolean(moduleName + "_" + key, defValue);
    }

    public boolean getBoolean(String key, boolean defValue) {
        return getBoolean(MODULE_DEFAULT, key, defValue);
    }

    public void saveBoolean(String moduleName, String key, boolean value) {
        saveBoolean(moduleName, key, value, false);
    }

    public void saveBoolean(String moduleName, String key, boolean value, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isSync || isBelowGingerBread()) {
                getPreferences().edit().putBoolean(moduleName + "_" + key, value).commit();
            } else {
                getPreferences().edit().putBoolean(moduleName + "_" + key, value).apply();
            }
        }
    }

    public void saveBoolean(String key, boolean value) {
        saveBoolean(MODULE_DEFAULT, key, value);
    }

    private Map<String, ?> getAll(String moduleName, boolean ignoreKeyPrefix) {
        Map<String, ?> allData = getPreferences().getAll();
        Map<String, Object> moduleData = new HashMap<String, Object>();
        Set<String> keySet = allData.keySet();
        for (String key : keySet) {
            String indexStr = moduleName + "_";
            if (key != null && key.startsWith(indexStr)) {
                String k = ignoreKeyPrefix ? key.substring(indexStr.length()) : key;
                moduleData.put(k, allData.get(key));
            }
        }
        return moduleData;
    }

    public Map<String, ?> getAll(String moduleName) {
        return getAll(moduleName, false);
    }

    public Map<String, ?> getAllIgnoreKeyPrefix(String moduleName) {
        return getAll(moduleName, true);
    }

    public void remove(String moduleName, String key, boolean isSync) {
        if (moduleName != null && key != null) {
            if (isBelowGingerBread() || isSync) {
                getPreferences().edit().remove(moduleName + "_" + key).commit();
            } else {
                getPreferences().edit().remove(moduleName + "_" + key).apply();
            }
        }
    }

    public void remove(String moduleName, String key) {
        remove(moduleName, key, false);
    }

    public void remove(String key, boolean isSync) {
        remove(MODULE_DEFAULT, key, isSync);
    }

    public void remove(String key) {
        remove(key, false);
    }

    public boolean contains(String moduleName, String key) {
        if (moduleName != null && key != null) {
            return getPreferences().contains(moduleName + "_" + key);
        }
        return false;
    }

    public void clear(String moduleName) {
        SharedPreferences.Editor editor = getPreferences().edit();

        Map<String, ?> moduleData = getAll(moduleName);
        Set<String> keySet = moduleData.keySet();
        for (String key : keySet) {
            editor.remove(key);
        }

        if (isBelowGingerBread()) {
            editor.commit();
        } else {
            editor.apply();
        }
    }

    /**
     * below API level 9 should not use apply method
     *
     * @return
     */
    private boolean isBelowGingerBread() {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD;
    }

    public void registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {
        getPreferences().registerOnSharedPreferenceChangeListener(listener);
    }

    public void unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {
        getPreferences().unregisterOnSharedPreferenceChangeListener(listener);
    }
}
